package cn.yto.print;

import cn.yto.print.config.ThreadPoolManager;
import cn.yto.print.config.i18n.I18nResourceManager;
import cn.yto.print.constants.AssistantConstants;
import cn.yto.print.controller.IndexController;
import cn.yto.print.enums.MessageTypeEnum;
import cn.yto.print.system.MySplashScreen;
import cn.yto.print.system.SpringContextHolder;
import cn.yto.print.system.SystemTrayManager;
import cn.yto.print.system.version.SystemUpdateChecker;
import cn.yto.print.utils.CommonUtil;
import cn.yto.print.utils.FileLockUtil;
import cn.yto.print.view.IndexView;
import de.felixroske.jfxsupport.AbstractJavaFxApplicationSupport;
import javafx.application.Platform;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;

@Slf4j
@MapperScan("cn.yto.print.sqlite.dao")
@SpringBootApplication
public class AssistantApplication extends AbstractJavaFxApplicationSupport implements ApplicationRunner {

    public static void main(String[] args) {

        long maxHeapSizeMb = Optional.of(Runtime.getRuntime()).map(rt -> rt.maxMemory() / (1024 * 1024)).orElse(0L);
        log.info("======================== Max Heap Size: {} MB ========================", maxHeapSizeMb);

        Thread.setDefaultUncaughtExceptionHandler((t, e) -> log.error("【全局未捕获的线程异常】", e));

        // 获取版本号
        String appVersion = Optional.ofNullable(CommonUtil.getAppConfig(AssistantConstants.APP_VERSION)).map(String::valueOf).orElse("");
        System.setProperty(AssistantConstants.APP_VERSION, appVersion);

        // 版本信息
        log.info("======================== App Version：{}   Java Version: {} =========================",
                appVersion, Optional.ofNullable(System.getProperty("java.version")).orElse(""));

        if (!Boolean.TRUE.equals(Optional.of(FileLockUtil.getFileLock()).filter(Boolean::booleanValue).orElse(false))) {
            Runnable activateInstance = () -> CommonUtil.activeRunInstance(
                    "localhost", CommonUtil.getAppConfig(AssistantConstants.APP_SOCKET));
            activateInstance.run();
            System.exit(0);
        }

        // 启动应用
        Consumer<String[]> launcher = arguments -> launch(AssistantApplication.class, IndexView.class, new MySplashScreen(), arguments);
        launcher.accept(args);
    }

    @Override
    public void run(ApplicationArguments args) {
        Platform.runLater(() -> {
            ((Supplier<SystemTrayManager>) () -> new SystemTrayManager(getStage())).get().addSystemTray();
            getStage().setOnShown(event -> {
                String message = Stream.of(CommonUtil.getAppConfig(AssistantConstants.APP_VERSION),
                        CommonUtil.getAppConfig(AssistantConstants.SERVER_PORT)).collect(() ->
                                new StringBuilder(I18nResourceManager.getInstance().get("index.console.application")),
                        (sb, s) -> sb.append(String.format(" %s", s)), StringBuilder::append).toString();
                SpringContextHolder.getBean(IndexController.class).addConsoleLog(message, MessageTypeEnum.INFO);
            });
        });

        // 检查更新
        ThreadPoolManager.getExecutorService().execute(() -> {
            Runnable checker = () -> SystemUpdateChecker.checkForUpdate(false);
            checker.run();
        });
    }

    @Override
    public void init() throws Exception {
        super.init();
    }

    @Override
    public void start(Stage stage) throws Exception {
        super.start(stage);
    }

    @Override
    public void beforeInitialView(Stage stage, ConfigurableApplicationContext ctx) {
        Optional.ofNullable(stage).ifPresent(s -> s.setResizable(false));
        super.beforeInitialView(stage, ctx);
    }

    @Override
    public void stop() throws Exception {
        try {
            FileLockUtil.releaseLock();
        } finally {
            super.stop();
        }
    }

    @Override
    public Collection<Image> loadDefaultIcons() {
        return Optional.ofNullable(getClass().getResource("/image/icon.png"))
                .map(url -> Collections.singletonList(new Image(url.toExternalForm())))
                .orElse(Collections.emptyList());
    }

}
